package com.zmj.registry;

import com.zmj.annotion.RpcService;
import com.zmj.handler.RPCServerHandler;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.*;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.handler.codec.LengthFieldBasedFrameDecoder;
import io.netty.handler.codec.LengthFieldPrepender;
import io.netty.handler.codec.serialization.ClassResolvers;
import io.netty.handler.codec.serialization.ObjectDecoder;
import io.netty.handler.codec.serialization.ObjectEncoder;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;

import java.util.HashMap;
import java.util.Map;

/**
 *
 * @author zhangmj
 * @date 2018/9/22 23:22
 */
@Slf4j
public class RPCServer {

    /**
     * 1 服务注册 一定要获得服务的注册名称、服务地址
     * 2 监听 根据服务的 address 进行监听
     */
    private IServiceRegistryCenter serviceRegistryCenter;
    private  String serviceAddress;

    /**
     * key:服务名称  value:服务对象
     */
    Map<String,Object> handlerMap =  new HashMap<String, Object>();

    public RPCServer(IServiceRegistryCenter serviceRegistryCenter, String serviceAddress) {
        this.serviceRegistryCenter = serviceRegistryCenter;
        this.serviceAddress = serviceAddress;
    }


    /**
     * 使用一个方法bind：服务名称--服务对象
     * @param services
     */
    public void bind(Object... services){
        // 遍历出传入了多少个服务对象
        for (Object service:services) {
            RpcService annotation = service.getClass().getAnnotation(RpcService.class);
            String serviceName = annotation.value().getName();
            handlerMap.put(serviceName,service);
        }
    }

    public void registerAndListen() {
        log.info("服务端接收信息：");
        // 1 注册服务地址，先遍历 handlerMap中有多少个服务名称
        for (String serviceName:handlerMap.keySet()) {
            // 注册服务名称和服务地址
            serviceRegistryCenter.registry(serviceName,serviceAddress);
        }
        // 2 监听端口，并且要进行与客户端的通信 socket
        // Netty   NIO
        try {
            EventLoopGroup bossGroup = new NioEventLoopGroup();
            EventLoopGroup workerGroup = new NioEventLoopGroup();
            // 启动 Netty 服务
            ServerBootstrap bootstrap = new ServerBootstrap();
            bootstrap.group(bossGroup,workerGroup);
            bootstrap.channel(NioServerSocketChannel.class);
            // springmvc web.xml DispacherServlet Handler
            bootstrap.childHandler(new ChannelInitializer<SocketChannel>() {
                @Override
                protected void initChannel(SocketChannel channel) throws Exception {
                    // 业务代码在这里写
                    ChannelPipeline pipeline = channel.pipeline();
                    // 如果你用 Netty 进行编程的话，只需要关注 handler即可，NIO BIO 一坨不用管了
                    pipeline.addLast("frameDecoder",new LengthFieldBasedFrameDecoder(Integer.MAX_VALUE,0,4,0,4));
                    pipeline.addLast("frameEncoder",new LengthFieldPrepender(4));
                    pipeline.addLast("encoder",new ObjectEncoder());
                    pipeline.addLast("decoder",new ObjectDecoder(Integer.MAX_VALUE, ClassResolvers.cacheDisabled(null)));
                    // 假如自己要写一个 Handler, 一定是和客户端进行打交道 Socket.getI
                    pipeline.addLast("handler",new RPCServerHandler(handlerMap));
                }
            }).option(ChannelOption.SO_BACKLOG,128).childOption(ChannelOption.TCP_NODELAY,true);
            // 通过 Netty 进行监听 8080
            String[] address = serviceAddress.split(":");
            String ip = address[0];
            int port = Integer.valueOf(address[1]);
            ChannelFuture future = bootstrap.bind(ip, port).sync();
            log.info("Netty 服务端启动成功,等待客户端的连接：");
            future.channel().closeFuture().sync();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

}
